class myPromise {
  // 添加状态
  static PENDING = 'pending'
  static FULFILLED = 'fulfilled'
  static REJECTED = 'rejected'

  constructor(func) {
    this.PromiseState = myPromise.PENDING
    this.PromiseResult = null
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []
    // 为函数绑定this指向 否则执行时其实this指向丢失了
    // 使用bind 是为了返回一个新的函数 而不是像apply call一样直接执行
    try {
      func(this.resolve.bind(this), this.reject.bind(this))
    } catch (err) {
      this.reject(err)
    }
  }
  resolve(result) {
    // 状态只能更变一次
    setTimeout(() => {
      if (this.PromiseState === myPromise.PENDING) {
        this.PromiseState = myPromise.FULFILLED
        this.PromiseResult = result
        // resolve 时执行
        this.onFulfilledCallbacks.forEach((item) => {
          item(result)
        });
      }
    })
  }
  reject(reason) {
    setTimeout(() => {
      if (this.PromiseState === myPromise.PENDING) {
        this.PromiseState = myPromise.REJECTED
        this.PromiseResult = reason
        this.onRejectedCallbacks.forEach((item) => {
          item(reason)
        })
      }
    })
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }

    const promise2 = new myPromise((resolve, reject) => {
      if (this.PromiseState == myPromise.PENDING) {
        this.onFulfilledCallbacks.push(() => {
          try {
            let x = onFulfilled(this.PromiseResult)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
        this.onRejectedCallbacks.push(() => {
          try {
            let x = onRejected(this.PromiseResult)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.PromiseState == myPromise.FULFILLED) {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.PromiseResult)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        });
      }
      if (this.PromiseState == myPromise.REJECTED) {
        setTimeout(() => {
          try {
            let x = onRejected(this.PromiseResult)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        });
      }
    })
    return promise2
  }
}


/**
 * 对 resolve、reject进行改造增强 针对resolve和reject中不同值的情况 进行处理
 * @param {promise} promise2 promise1.then方法返回的新的promise对象
 * @param {[type]}  x        promise1中onFulfilled或onRejected的返回值
 * @param {[type]}  resolve  promise2的resolve方法
 * @param {[type]}  reject   promise2的reject方法
 */

function resolvePromise(promise2, x, resolve, reject) {
  if(x === promise2){
    // 若 x 和 promise2 指向同一个对象,以TypeError为原因拒绝执行promise
    return reject(new TypeError("chaining cycle detected for promise"))
  }

  if(x instanceof myPromise){
    if(x.PromiseState === myPromise.PENDING){
      // 若 x 处于 pending ,promise须保持为等待态 直至x被执行或拒绝
      x.then(
        y => {
          // console.log("@",y)
          resolvePromise(promise2,y,resolve,reject)
        }
      )
    }else if(x.PromiseState === myPromise.FULFILLED){
      resolve(x.PromiseResult)
    }else if(x.PromiseState === myPromise.REJECTED){
      reject(x.PromiseResult)
    }
  }else if(x !== null && ((typeof x === 'object' || typeof x === 'function'))){
    // 如果 x 为对象 或函数
    try{
      var then = x.then
    }catch(e){
      return reject(e)
    }

    // 若 then 是函数 则将x作为函数的作用域this调用
    // 传递两个回调作为参数 第一个参数为 resolvePromise 第二个为 rejectPromise
    if(typeof then === 'function'){
      let called = false
      try{
        // call 绑定其 this 指向
        then.call(
          x,
          y => {
            if(called) return
            called = true
            resolvePromise(promise2,y,resolve,reject)
          },
          r => {
            if(called) return
            called = true
            reject(r)
          }
        )
      }catch(e){
        // 若调用 then 抛出了异常 e
        // 若resolvePromise 或 rejectPromise 已经被调用,则忽略
        if(called) return
        called = true

        // 否则以 e 为拒因拒绝 promise
        reject(e)
      }
    }else{
      // 若 then 不是函数 则以x为参数执行promise
      resolve(x)
    }
  }else{
    // 如果 x 不为对象或函数,以x为参数执行 promise
    return resolve(x)
  }
}